package com.sprouting.personal.controller;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.json.JSONUtil;
import com.sprouting.personal.interfaces.common.CacheKey;
import com.sprouting.personal.interfaces.common.Constant;
import com.sprouting.personal.model.common.ResultJson;
import com.sprouting.personal.model.common.jsr.AddGroup;
import com.sprouting.personal.model.entity.*;
import com.sprouting.personal.model.vo.LoginSuccessVo;
import com.sprouting.personal.model.vo.RegisterUserPram;
import com.sprouting.personal.service.*;
import com.sprouting.personal.utils.CheckTool;
import com.sprouting.personal.utils.EntityTool;
import com.sprouting.personal.utils.IdTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 开放的控制层
 *
 * RestController  声明该类属于Controller。与@Controller不同的是，@RestController可以返回JSON内容，而单独@Controller则不可以。@RestController无法跳转页面
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2022/7/26 1:24
 */
@RequestMapping("/open")
@RestController
@Slf4j
public class OpenController {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PowerService powerService;
    @Autowired
    private MemberFamilyService memberFamilyService;
    @Autowired
    private ConfigService configService;

    /**
     * 系统登录加密解密的key
     */
    @Value("${login.password.key}")
    private String loginPasswordKey;


    /**
     * 获取用户加密解密的key
     * @return
     */
    @RequestMapping("/getKey")
    public ResultJson<String> getKey(){
        return ResultJson.success(loginPasswordKey);
    }

    /**
     * 获取注册页跳往哪一个
     * @return
     */
    @GetMapping("/getRegisterPage")
    public ResultJson getRegisterPage(){
        return ResultJson.success(configService.getConfigByCode(Constant.ConfigCode.REGISTER_PAGE, null));
    }

    /**
     * 注册用户到系统中
     * @param registerUserPram 注册参数
     * @return
     */
    @PostMapping("/register")
    public ResultJson register(@Validated({AddGroup.class}) RegisterUserPram registerUserPram){
        User userDb = userService.getUserServiceByLoginUser(registerUserPram.getLoginUser());
        if (userDb != null){
            return ResultJson.error("登录用户名已注册");
        }

        // 解密参数以及验证密码
        try {
            DES des = SecureUtil.des(loginPasswordKey.getBytes(Constant.Encoded.UTF));
            log.info("加密后用户名：{},密码:{}", des.encryptHex(registerUserPram.getLoginUser()), des.encryptHex(registerUserPram.getPassword()));
            registerUserPram.setLoginUser(des.decryptStr(registerUserPram.getLoginUser().trim()));
            registerUserPram.setPassword(des.decryptStr(registerUserPram.getPassword().trim()));
        } catch (Exception e) {
            log.error("[登录] 对用户名或密码解密错误，用户名：{}，密码：{}", registerUserPram.getLoginUser(), registerUserPram.getPassword());
            return ResultJson.error("非法登录请求");
        }

        User user = BeanUtil.copyProperties(registerUserPram, User.class);
        user.setId(IdTool.getId());
        user.setSalt(IdTool.getId());
        // todo 密码理论上应该进行加密，但考虑到个人用的系统，暂时不做这么复杂，直接明文保存，设计中密码应该加盐处理
        EntityTool.buildSaveBase(user, Constant.DefaultValue.SYS_USER);

        MemberFamily memberFamily = new MemberFamily();
        EntityTool.buildSaveBase(memberFamily, Constant.DefaultValue.SYS_USER);
        memberFamily.setId(user.getId());
        memberFamily.setUserId(user.getId());
        memberFamily.setUserName(registerUserPram.getUserName());
        memberFamily.setSort(Constant.DefaultValue.SORT);

        // 绑定角色。暂时这一块不做太复杂，也不需要做授权等，暂时就使用普通角色即可，后续可以改进
        UserRole userRole = new UserRole();
        userRole.setId(IdTool.getId());
        userRole.setUserId(user.getId());
        userRole.setRoleId(Constant.DefaultValue.ORDINARY);

        userService.saveUser(user, memberFamily, userRole);
        return ResultJson.success("注册成功");
    }

    /**
     * 登录
     * @param loginUser 登录用户名
     * @param password 密码
     * @return
     */
    @PostMapping("/loginPc")
    public ResultJson<LoginSuccessVo> loginPc(String loginUser, String password){
        String msg = checkLoginPram(loginUser, password);
        if (msg != null){
            return ResultJson.error(msg);
        }

        // 解密参数以及验证密码
        loginUser = loginUser.trim();
        password = password.trim();

        try {
            DES des = SecureUtil.des(loginPasswordKey.getBytes(Constant.Encoded.UTF));
            log.info("加密后用户名：{},密码:{}", des.encryptHex(loginUser), des.encryptHex(password));
            loginUser = des.decryptStr(loginUser);
            password = des.decryptStr(password);
        } catch (Exception e) {
            log.error("[登录] 对用户名或密码解密错误，用户名：{}，密码：{}", loginUser, password);
            return ResultJson.error("非法登录请求");
        }

        User userDb = userService.getUserServiceByLoginUser(loginUser);
        if (userDb == null){
            return ResultJson.error("账号或密码错误");
        }
        // 注册的时候暂时现在没用到盐，根据实际情况来处理
        if (!userDb.getPassword().equals(password)){
            return ResultJson.error("登录密码错误");
        }

        //3、--- 登陆成功后
        StpUtil.login(userDb.getId(), Constant.LoginType.PC);
        // 获取当前账号ID的session[有三种session，当前账号id的Session，当前token的专属Session，自定义Session指的是以一个特定的值作为SessionId来分配的Session]
        // 只使用当前用户ID的session
        // 3.1--- 加载到session中
        SaSession session = StpUtil.getSession(true);
        // 用户信息
        session.set(CacheKey.SaTokenSession.SESSION_KEY_USER, userDb);
        // 角色信息
        List<Role> roleList = roleService.getRoleByUserId(userDb.getId());
        List<String> roleNameAll = roleList.stream().map(Role::getName).distinct().collect(Collectors.toList());
        session.set(CacheKey.SaTokenSession.SESSION_KEY_ROLE, JSONUtil.toJsonStr(roleNameAll));
        // 权限信息
        List<String> roleIdAll = roleList.stream().map(Role::getId).distinct().collect(Collectors.toList());
        List<Power> powerList = powerService.getPowerByRoleId(roleIdAll);
        List<String> powerResourceAll = powerList.stream().map(Power::getResource).distinct().collect(Collectors.toList());
        session.set(CacheKey.SaTokenSession.SESSION_KEY_POWER, JSONUtil.toJsonStr(powerResourceAll));

        // 封装返回的数据
        MemberFamily memberFamily = memberFamilyService.getMemberFamilyById(userDb.getId());
        LoginSuccessVo loginSuccessVo = new LoginSuccessVo();
        loginSuccessVo.setTokenName(StpUtil.getTokenName());
        loginSuccessVo.setTokenValue(StpUtil.getTokenValue());
        loginSuccessVo.setMemberFamily(memberFamily);
        loginSuccessVo.setPowerSet(powerResourceAll);
        loginSuccessVo.setRoleSet(roleNameAll);
        return ResultJson.success(loginSuccessVo);
    }

    /**
     * 校验登录参数
     * @param loginUser 登录用户名
     * @param password 登录密码
     * @return
     */
    private String checkLoginPram(String loginUser, String password){
        if (CheckTool.checkNull(loginUser)){
            return "请输入登录用户名";
        }
        if (CheckTool.checkNull(password)){
            return "请输入登录密码";
        }

        return null;
    }

}
